#include <am.h>
#include <amdev.h>
#include <nemu.h>
#include <klib.h>

static uint32_t swidth;
static uint32_t sheight;


size_t __am_video_read(uintptr_t reg, void *buf, size_t size) {
  switch (reg) {
    case _DEVREG_VIDEO_INFO: {
      _DEV_VIDEO_INFO_t *info = (_DEV_VIDEO_INFO_t *)buf;
      uint32_t wh = inl(SCREEN_ADDR);
      info->width = wh >> 16;
      info->height = (wh << 16) >> 16 ;
      swidth = info->width;
      sheight = info->height;
      return sizeof(_DEV_VIDEO_INFO_t);
    }
  }
  return 0;
}

size_t __am_video_write(uintptr_t reg, void *buf, size_t size) {
  switch (reg) {
    case _DEVREG_VIDEO_FBCTL: {
      _DEV_VIDEO_FBCTL_t *ctl = (_DEV_VIDEO_FBCTL_t *)buf;
      uint32_t x = ctl->x, y = ctl->y, w = ctl->w, h = ctl->h;
      uint32_t *pixels = ctl->pixels;
      uint32_t cp_bytes = sizeof(uint32_t) * ((w < (swidth - x)) ? w : (swidth - x));

      if(ctl->sync) 
        outl(SYNC_ADDR, 0);
        
      for (int j = 0; j < h && y + j < sheight; j ++) {
        uint32_t* fb = (uint32_t*)FB_ADDR;
        memcpy(&fb[(y + j) * swidth + x],pixels,cp_bytes);
        pixels += w;
      }
      return size;
    }
  }
  return 0;
}

void __am_vga_init() {
  int i;
  int size = screen_width() * screen_height();
  uint32_t *fb = (uint32_t *)(uintptr_t)FB_ADDR;
  for (i = 0; i < size; i ++) fb[i] = i;
  draw_sync();
}
